﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;
using System.IO.Packaging;
using Microsoft.Xna.Framework;

namespace Engine.MarchCube
{
    public struct OutResult
    {
        public byte[] EType;
        public float Iso;
        public bool isNull;
    }
    public class ElementData
    {
        byte[, ,] m_data;
        int m_Size;
        int Count = 0;
        string m_FileName;
        Vector3 m_position;
        Engine.Voxel.IBaseMaterial mat;
        Random rnd;
        public ElementData(int size,Vector3 pos,string FileName)
        {
            m_data = new byte[size, size, size];
            m_Size = size;
            m_position =pos;
            m_FileName = FileName;
        }
        public void RndDat()
        {
            mat = Engine.Voxel.Materials.GetMat("Ground");
            Count = 0;
            rnd = new Random(Environment.TickCount);
            for (int i = 1; i < m_Size-1; i++)
            {
                for (int t = 1; t < m_Size - 1; t++)
                {
                    for (int k =1; k < m_Size - 1; k++)
                    {
                        m_data[i, t, k] = (byte)rnd.Next(0, 255);
                    }
                }
            }
        }
        public ElementData(string FileName)
        {
            m_FileName = FileName;
            m_data = LoadData();
        }
        public bool Save(string SpecificFile = "")
        {
            string FileName = m_FileName;
            if (SpecificFile != "")
            {
                FileName = SpecificFile;
                m_FileName = SpecificFile;
            }

            if (m_data != null)
            {
                using (Package zip = Package.Open(FileName, FileMode.OpenOrCreate))
                {

                    Uri Head = PackUriHelper.CreatePartUri(new Uri("Header.dat", UriKind.Relative));
                    if (zip.PartExists(Head))
                    {
                        zip.DeletePart(Head);
                    }
                    PackagePart headPart = zip.CreatePart(Head, "", CompressionOption.Normal);
                    byte[] bufer = new byte[16];
                    using (Stream s = headPart.GetStream())
                    {


                        Array.Copy(BitConverter.GetBytes(m_Size), 0, bufer, 0, 4);
                        Array.Copy(BitConverter.GetBytes(m_position.X), 0, bufer, 4, 4);
                        Array.Copy(BitConverter.GetBytes(m_position.Y), 0, bufer, 8, 4);
                        Array.Copy(BitConverter.GetBytes(m_position.Z), 0, bufer, 12, 4);
                        s.Write(bufer, 0, bufer.Length);
                    }
                    //   temp = new byte[m_Size, m_Size, m_Size];
                    for (int y = 0; y < m_Size; y++)
                    {
                        Uri TempDat = PackUriHelper.CreatePartUri(new Uri("y" + y + ".dat", UriKind.Relative));
                        bufer = new byte[m_Size * m_Size];
                        if (zip.PartExists(TempDat))
                        {
                            zip.DeletePart(TempDat);
                        }
                        headPart = zip.CreatePart(TempDat, "", CompressionOption.Normal);

                        using (Stream s = headPart.GetStream())
                        {
                           
                            for (int x = 0; x < m_Size; x++)
                            {
                                for (int z = 0; z < m_Size; z++)
                                {
                                    int index = x * m_Size + z;
                                    bufer[index]=m_data[x, y, z];
                                }
                            }
                            s.Write(bufer, 0, bufer.Length);
                        }
                    }

                    zip.Close();

                }
                
                return true;
            }
            return false;
        }

        public bool load(string SpecificFile = "")
        {
            m_data = LoadData(SpecificFile);
            if (m_data == null)
            {
                return false;
            }
            return true;
        }
        private byte[, ,] LoadData(string SpecificFile = "")
        {
            string FileName = m_FileName;
            if (SpecificFile != "")
            {
                FileName = SpecificFile;
                m_FileName = SpecificFile;
            }


            FileInfo fi = new FileInfo(FileName);
            byte[, ,] temp = null;
            if (fi.Exists)
            {
                using (Package zip = Package.Open(FileName, FileMode.Open))
                {
                    Uri Head = PackUriHelper.CreatePartUri(new Uri("Header.dat", UriKind.Relative));
                    if (zip.PartExists(Head))
                    {
                        PackagePart headPart = zip.GetPart(Head);
                        Stream s = headPart.GetStream();
                        byte[] bufer = new byte[s.Length];
                        s.Read(bufer, 0, bufer.Length);
                        m_Size = BitConverter.ToInt32(bufer, 0);
                        m_position = new Vector3(
                            BitConverter.ToSingle(bufer, 4),
                             BitConverter.ToSingle(bufer, 8),
                              BitConverter.ToSingle(bufer, 12)
                                    );
                        temp = new byte[m_Size, m_Size, m_Size];
                        for (int y = 0; y < m_Size; y++)
                        {
                            Uri TempDat = PackUriHelper.CreatePartUri(new Uri("y" + y + ".dat", UriKind.Relative));
                            headPart = zip.GetPart(TempDat);
                            bufer = new byte[m_Size * m_Size];
                            s = headPart.GetStream();
                            s.Read(bufer, 0, bufer.Length);
                            for (int x = 0; x < m_Size; x++)
                            {
                                for (int z = 0; z < m_Size; z++)
                                {
                                    int index = x * m_Size + z;
                                    temp[x, y, z] = bufer[index];
                                }
                            }
                        }

                    }

                }
            }
            return temp;
        }
        public OutResult chekPos(double xPos, double yPos, double zPos)
        {
            OutResult res = new OutResult();
            res.isNull = true;

            int xMin = (int)(xPos-m_position.X);
            int yMin = (int)(yPos - m_position.Y);
            int zMin = (int)(zPos - m_position.Z);
            float resD = 0;
            List<byte> tmp = new List<byte>(); 
            for (int x = xMin; x <= xMin + 1; x++)
            {
                for (int y = yMin; y <= yMin + 1; y++)
                {
                    for (int z = zMin; z <= zMin + 1; z++)
                    {
                        if (x < m_Size && y < m_Size && z < m_Size
                            &&
                            x>-1 && y>-1 &&z>-1 
                            )
                        {


                            if (m_data[x, y, z] > 120)
                            {
                                resD++;
                                tmp.Add(m_data[x, y, z]);
                            }
                        }
                    }
                }
            }
            resD /= 4;
            if (resD > 0)
            {
                res.EType = tmp.ToArray();
                res.Iso = resD;
                res.isNull = false;
            }
            return res;

        }
        public Color GetColor(double xPos, double yPos, double zPos)
        {
            Color res = Color.Transparent;  
            int xMin = (int)(xPos - m_position.X);
            int yMin = (int)(yPos - m_position.Y);
            int zMin = (int)(zPos - m_position.Z);
            Vector4 resD=Vector4.Zero;
            List<byte> tmp = new List<byte>();
           
            for (int x = xMin; x <= xMin + 1; x++)
            {
                for (int y = yMin; y <= yMin + 1; y++)
                {
                    for (int z = zMin; z <= zMin + 1; z++)
                    {
                        if (x < m_Size && y < m_Size && z < m_Size
                            &&
                            x > -1 && y > -1 && z > -1
                            )
                        {


                            if (m_data[x, y, z] > 120)
                            {
                                byte val=m_data[x, y, z];
                                
                                resD=resD+mat.MaterialColors[Count++].ToVector4();
                                if (Count>=mat.MaterialColors.Length)
                                {
                                    Count = 0; 
                                }
                            }
                        }
                    }
                }
            }
            resD /= 8;
            if (resD !=Vector4.Zero)
            {
                res = new Color(resD);
            }
            return res;

        }
    }
}
